# = StarFrame::Sprite::Collidable -- スプライトの衝突
require "starframe/sprite/collision"

module StarFrame
  class Sprite
    # = Sprite::Collidableモジュール
    # スプライト衝突モジュール。
    # 
    # Spriteクラスのサブクラス定義内でincludeし、collisionクラスメソッドで当たり判定を定義する。
    # 
    #   class CollidedSprite < StarFrame::Sprite
    #     collision :damage, Circle, 0, 0, 8 do |other|
    #       self.vanish
    #     end
    #   end
    module Collidable
      attr_accessor :collisions
      
      def self.included sprite #:nodoc:
        sprite.extend ClassMethods
        sprite.module_eval do
          alias_method_chain :call_init, :collision
          
          @collisions = Hash.new{ |hash, key| hash[key] = [] }
        end
      end
      
      def call_init_with_collision *args #:nodoc:
        @collisions = {}
        self.class.collisions.each do |name, collision|
          @collisions[name] = collision.build(self)
        end
        call_init_without_collision *args
      end
      
      # 衝突しているかどうかを判定する
      def collide? other, name, other_name
        @collisions[name].collide?(other.collisions[other_name])
      end
      
      # 衝突しているかどうかを判定し、衝突していれば衝突処理を実行する
      def collide other, name, other_name
        @collisions[name].collide(other.collisions[other_name])
      end
      
      # 当たり判定を取得
      def collision name
        @collisions[name]
      end
      
      module ClassMethods
        attr_accessor :collisions #:nodoc:
        
        # 当たり判定を定義
        # 
        # StarFrame::Sprite::Collisionクラスのサブクラスのインスタンスを新規に作成し、Spriteに設定する。
        # 
        # params
        #   name - 当たり判定の名前。衝突判定をする当たり判定を選ぶ際などに使用される。
        #   collision - 当たり判定の種類。クラスを直接渡す。
        #   options - 当たり判定に渡されるパラメタ。
        #   &block - 衝突時に呼ばれるメソッド定義。
        def collision name, collision, *options, &block
          @collisions[name] = StarFrame::Sprite::Collision::Builder.new(self, name, collision, *options, &block)
        end
        
        def inherited klass #:nodoc:
          klass.collisions = @collisions.dup
          super
        end
      end
    end
    
    class Collection
      def collide others, name, others_name
        result = false
        each do |sprite|
          others.each do |other|
            result |= sprite.collide other, name, others_name
          end
        end
        result
      end
    end
  end
end
